package cz.data.common.security.core.token;

import cz.data.common.base.SimpleDataResponse;
import cz.data.common.core.DataConstant;
import cz.data.common.core.DataUser;
import cz.data.common.exception.DataException;
import cz.data.common.redis.service.RedisService;
import cz.data.common.security.utils.SecurityUtils;
import cz.data.domain.security.rpc.OAuth2ServiceFeign;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.CredentialsExpiredException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.jwt.Jwt;

import java.util.Objects;

public class JwtTokenAuthenticationProvider implements AuthenticationProvider {
    private static final String CACHE_PREFIX = DataConstant.Token.JTI_CACHE_PREFIX;
    private final OAuth2ServiceFeign oAuth2ServiceFeign;
    private final RedisService redisService;

    public JwtTokenAuthenticationProvider(OAuth2ServiceFeign oAuth2ServiceFeign, RedisService redisService) {
        this.oAuth2ServiceFeign = oAuth2ServiceFeign;
        this.redisService = redisService;
    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        if (authentication instanceof JwtTokenAuthentication) {
            JwtTokenAuthentication jwtTokenAuthentication = (JwtTokenAuthentication) authentication;
            DataUser userinfo = this.userinfo(jwtTokenAuthentication.getJwt());
            if (Objects.nonNull(userinfo)) {
                jwtTokenAuthentication.setUserinfo(userinfo);
                jwtTokenAuthentication.setAuthenticated(true);
                return jwtTokenAuthentication;
            }
        }
        return null;
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return JwtTokenAuthentication.class.isAssignableFrom(authentication);
    }

    public DataUser userinfo(Jwt jwt) {
        String jti = jwt.getId();
        Object value = redisService.get(CACHE_PREFIX + jti);
        if (Objects.isNull(value)) {
            String tokenValue = SecurityUtils.addBearerTokenType(jwt.getTokenValue());
            SimpleDataResponse<DataUser> response = oAuth2ServiceFeign.userinfo(tokenValue);
            if (Objects.isNull(response)) {
                throw new DataException("用户认证失败,请稍后重试!");
            } else if (Boolean.TRUE.equals(response.getSuccess())) {
                DataUser dataUser = response.getData();
                if (Objects.nonNull(dataUser)) {
                    redisService.set(CACHE_PREFIX + jti, dataUser, 600L);
                }
                return dataUser;
            } else {
                throw new CredentialsExpiredException(response.getMsg());
            }
        } else {
            return (DataUser) value;
        }
    }
}
